home *** CD-ROM | disk | FTP | other *** search
/ Fritz: All Fritz / All Fritz.zip / All Fritz / FILES / ARTIENCE / INFER.LZH / INFER.PAS < prev    next >
Pascal/Delphi Source File  |  1988-10-24  |  8KB  |  357 lines

  1. Program Infer;
  2.  
  3. {
  4.   Norman Newman, Kibbutz Mishmar David.
  5.   OMSI Pascal-2 version  - 14 Dec 1986
  6.   Turbo Pascal-3 version - 21 Mar 1988
  7.   Updated to TP 4 - October 1988. No changes needed.
  8.  
  9.   This program solves the hypothetical syllogism. For more help,
  10.   see the file 'infer.txt'.
  11.  
  12.   Permission is granted to use this program, or portions thereof,
  13.   for non-commercial purposes. All other rights are reserved to
  14.   the original author.
  15.  
  16. }
  17.  
  18. type
  19.  string50 = string[50];
  20.  
  21.  pointer = ^pointer_type;
  22.  pointer_type = record
  23.                  name: string50;
  24.                  head: set of 0..255;
  25.                  next: pointer
  26.                 end;
  27.  
  28. var
  29.  class_front, class_rear, data_front, data_rear: pointer;
  30.  in_line: string50;
  31.  i, class_count: integer;
  32.  
  33. { ------------------------------------------------------- }
  34. {                 Low level procedures                    }
  35. { ------------------------------------------------------- }
  36.  
  37.  procedure strip_article (var s: string50);
  38.   var
  39.    i: integer;
  40.  
  41.   begin
  42.    i:= 0;
  43.    if pos ('a',s) = 1 then i:= 3
  44.    else if pos ('an', s) = 1 then i:= 4
  45.    else if pos ('the', s) = 1 then i:= 5;
  46.    if i > 0 then s:= copy (s, i, length(s) + 1 - i)
  47.   end;
  48.  
  49.  procedure parse (var main, left, right: string50;
  50.                   place, count: integer);
  51.   { This procedure accepts as input the string 'main', puts the
  52.     first place - 1 characters into the string 'left', and puts
  53.     the rest (less count) into 'right'. All leading articles are
  54.     stripped from the substrings.
  55.   }
  56.  
  57.   begin
  58.    left:= copy (main, 1, place - 1);
  59.    strip_article (left);
  60.    place:= place + count;
  61.    count:= length (main) - place;
  62.    right:= copy (main, place + 1, count);
  63.    strip_article (right)
  64.   end;
  65.  
  66.  function find_match (list: pointer;
  67.                       var s: string50): integer;
  68.   var
  69.    found: boolean;
  70.    i: integer;
  71.  
  72.   begin
  73.    found:= false;
  74.    i:= 0;
  75.    while list <> nil do
  76.     begin
  77.      i:= i + 1;
  78.      if list^.name = s
  79.       then
  80.        begin
  81.         found:= true;
  82.         list:= nil
  83.        end
  84.       else list:= list^.next
  85.     end;
  86.  
  87.    if found
  88.     then find_match:= i
  89.     else find_match:= 0
  90.   end;
  91.  
  92.  function get_list (list: pointer; n: integer): pointer;
  93.   { Return the n'th member of 'list' }
  94.   var
  95.    i: integer;
  96.  
  97.   begin
  98.    for i:= 1 to n - 1 do list:= list^.next;
  99.    get_list:= list
  100.   end;
  101.  
  102. { ------------------------------------------------------- }
  103. {                 High level procedures                   }
  104. { ------------------------------------------------------- }
  105.  
  106.  procedure declare (place: integer);
  107.   var
  108.    subject, object: string50;
  109.    p: pointer;
  110.    count: integer;
  111.  
  112.   begin
  113.    parse (in_line, subject, object, place, 3);
  114.    { 'is ' occupies 3 places }
  115.    place:= find_match (class_front, subject);
  116.  
  117.    { insert the subject if need be }
  118.    if place = 0
  119.     then
  120.      begin
  121.       class_count:= class_count + 1;
  122.       place:= class_count;
  123.       new (p);
  124.       with p^ do
  125.        begin
  126.         name:= subject;
  127.         head:= [];
  128.         next:= nil
  129.        end;
  130.  
  131.       if class_front = nil
  132.        then class_front:= p
  133.        else class_rear^.next:= p;
  134.       class_rear:= p
  135.      end;
  136.  
  137.    { insert the object }
  138.    count:= find_match (data_front, object);
  139.    if count = 0             { new object }
  140.     then
  141.      begin
  142.       new (p);
  143.       with p^ do
  144.        begin
  145.         name:= object;
  146.         head:= [place];
  147.         next:= nil
  148.        end;
  149.  
  150.       if data_front = nil
  151.        then data_front:= p
  152.        else data_rear^.next:= p;
  153.       data_rear:= p
  154.      end
  155.     else
  156.      begin
  157.       p:= get_list (data_front, count);
  158.       p^.head:= p^.head + [place]
  159.      end;
  160.  
  161.    writeln ('Noted')
  162.   end { declare };
  163.  
  164.  procedure inquire;
  165.   var
  166.    subject, object: string50;
  167.    place, count: integer;
  168.    found: boolean;
  169.  
  170.   procedure backtrack (place, count: integer;
  171.                        list: pointer;
  172.                        var found: boolean);
  173.    var
  174.     i: integer;
  175.     p, q: pointer;
  176.  
  177.    begin
  178.     if count > 0
  179.      then
  180.       begin
  181.        p:= get_list (list, count);
  182.        i:= 0;
  183.        repeat
  184.         i:= i + 1;
  185.         if i in p^.head
  186.          then
  187.           begin
  188.            found:= place = i;
  189.            if not found
  190.             then
  191.              begin
  192.               q:= get_list (class_front, i);
  193.               count:= find_match (data_front, q^.name);
  194.               backtrack (place, count, list, found)
  195.              end
  196.           end
  197.        until found or (i = class_count)
  198.       end
  199.    end { backtrack };
  200.  
  201.   begin { inquire }
  202.    { get rid of opening 'is ' }
  203.    in_line:= copy (in_line, 4, length(in_line) - 3);
  204.    { if there is a question mark at the end, remove it }
  205.    if in_line[length(in_line)] = '?'
  206.     then in_line[0]:= pred(in_line[0]);
  207.  
  208.    { strip initial article - if present }
  209.    strip_article (in_line);
  210.    { look for article separating the clauses }
  211.    place:= pos (' a ', in_line);
  212.    if place <> 0 then count:= 2
  213.    else
  214.     begin
  215.      place:= pos (' an ',in_line);
  216.      if place <> 0 then count:= 3
  217.      else
  218.       begin
  219.        place:= pos (' the ', in_line);
  220.        if place <> 0 then count:= 4
  221.       end
  222.     end;
  223.  
  224.    if place = 0 then writeln ('I don''t understand')
  225.    else
  226.     begin
  227.      parse (in_line, subject, object, place, count);
  228.      place:= find_match (class_front, subject);
  229.      if place = 0
  230.       then
  231.        begin
  232.         write ('I have no data concerning ');
  233.         writeln (subject)
  234.        end
  235.       else
  236.        begin
  237.         found:= false;
  238.         count:= find_match (data_front, object);
  239.         backtrack (place, count, data_front, found);
  240.         if found
  241.          then writeln ('Yes')
  242.          else writeln ('I don''t know')
  243.        end
  244.     end
  245.   end { inquire };
  246.  
  247.  procedure who_is (flag: boolean);
  248.   var
  249.    answers: set of 0..255;
  250.    subject: string50;
  251.    i: integer;
  252.    p: pointer;
  253.  
  254.   procedure find_answers (place: integer);
  255.    var
  256.     p, q: pointer;
  257.     i: integer;
  258.  
  259.    begin
  260.     if place > 0
  261.      then
  262.       begin
  263.        p:= get_list (data_front, place);
  264.        for i:= 1 to class_count do
  265.         if i in p^.head
  266.          then
  267.           begin
  268.            q:= get_list (class_front, i);
  269.            answers:= answers + [i];
  270.            find_answers (find_match (data_front, q^.name))
  271.           end
  272.       end
  273.    end { find_answers };
  274.  
  275.   begin { who is ? }
  276.    answers:= [];
  277.    { strip interrogative }
  278.    if flag
  279.     then i:= 7   { 'who is '}
  280.     else i:= 8;  { 'what is '}
  281.    in_line:= copy (in_line, i+1, length(in_line) - i);
  282.    { strip question mark, if present }
  283.    if in_line[length(in_line)] = '?'
  284.     then in_line[0]:= pred(in_line[0]);
  285.    subject:= in_line;
  286.    strip_article (subject);
  287.    find_answers (find_match(data_front, subject));
  288.  
  289.    if answers = []
  290.     then if flag
  291.      then writeln ('No one.')
  292.      else writeln ('Nothing.')
  293.     else for i:= 1 to class_count do
  294.      if i in answers
  295.       then
  296.        begin
  297.         p:= get_list (class_front, i);
  298.         writeln (p^.name, ' is ', in_line);
  299.        end
  300.   end { who is? };
  301.  
  302.  procedure requests;
  303.   var
  304.    place: integer;
  305.  
  306.   procedure print (list: pointer; place: integer);
  307.    begin
  308.     while list <> nil do
  309.      with list^ do
  310.       begin
  311.        if place in head then writeln (name);
  312.        list:= next
  313.       end
  314.    end;
  315.  
  316.   begin { requests }
  317.    { get rid of opening 'request' }
  318.    in_line:= copy (in_line, 9, length(in_line) - 8);
  319.    place:= find_match (class_front, in_line);
  320.    if place = 0
  321.     then writeln ('I have no data comncerning ', in_line)
  322.     else
  323.      begin
  324.       writeln (in_line, ' is ...');
  325.       print (data_front, place)
  326.      end
  327.   end { request };
  328.  
  329. begin { infer }
  330.  class_front:= nil;
  331.  data_front:= nil;
  332.  class_count:= 0;
  333.  
  334.  write ('-> ');
  335.  readln (in_line);
  336.  while (in_line <> 'bye') do
  337.   begin
  338.    if pos ('is ', in_line) = 1 then inquire
  339.    else if pos ('request ', in_line) = 1 then requests
  340.    else if pos ('who ', in_line) = 1 then who_is (true)
  341.    else if pos ('what ', in_line) = 1 then who_is (false)
  342.    else
  343.     begin
  344.      i:= pos (' is ', in_line);
  345.      if i <> 0
  346.       then declare (i)
  347.       else writeln ('What???')
  348.     end;
  349.  
  350.    writeln;
  351.    write ('-> ');
  352.    readln (in_line)
  353.   end
  354. end.
  355.  
  356.  
  357.